import os
import sys
import locale
import dbus.service
from dbus.mainloop.glib import DBusGMainLoop

from PyQt4.QtGui import QDesktopServices, QApplication
from PyQt4.QtGui import qApp, QStyle, QSystemTrayIcon, QShortcut, QKeySequence
from PyQt4.QtGui import QFileDialog
from PyQt4.QtCore import QObject
from PyQt4.QtCore import Qt
from PyQt4.QtCore import QString
from PyQt4.QtCore import  QEvent

from informer import Informer
from plugin import PluginManager
from ui.playlist import Playlist
from player import Player
from settings import set
from settings import get
from settings import save
from settings import configCreated
from trayicon import TrayIcon
import gst
from PyQt4.Qt import QTranslator
from ui.mainwindow import MainWindow
import dbus

MetaQObject = type(QObject)
MetaObject = type(dbus.service.Object)

class MetaPlayer(MetaQObject, MetaObject):
    """Dummy metaclass that allows us to inherit from both QObject and dbus.srvice.Object"""

    def __init__(cls, name, bases, dct):
        MetaObject.__init__(cls, name, bases, dct)
        MetaQObject.__init__(cls, name, bases, dct)

class Phonik(QObject, dbus.service.Object):
    __metaclass__ = MetaPlayer

    def __init__(self):
        QObject.__init__(self)
        dbus.service.Object.__init__(self)

        bus_name = dbus.service.BusName('com.phonik.PhonikInterface', bus=dbus.SessionBus())
        dbus.service.Object.__init__(self, bus_name, '/org/frankhale/helloservice')

        # app
        app = QApplication(sys.argv)
        app.setApplicationName("Phonik")


        # translations
        translator = QTranslator()
        if translator.load('../translations/phonik.' + locale.getdefaultlocale()[0].lower() + '.qm'):
            app.installTranslator(translator)

        # main components
        self.player = Player(self)

        self.mw = MainWindow()
        self.mw.show()
        #        self.mw.setWindowIcon(QIcon('../res/phonik.py.png'))

        self.informer = Informer()

        self.playlist = Playlist(self.informer)

        self.pm = PluginManager()
        self.pm.loadPlugins(self.mw, self.playlist, self.player, self.informer)

        #tray icon
        self.trayIcon = TrayIcon(self.mw)

        # set connections
        self.connect()

        self.hotKeys()

        # configuration
        self.readSettings()

        self.parserArgs()

        # run
        sys.exit(app.exec_())


    @dbus.service.method('com.phonik.PhonikInterface', in_signature='v', )
    def parserArgs(self, args=None):
        if not args:
            args = sys.argv[1:]

        for arg in args:
            if arg.endswith(".pls") or arg.endswith(".m3u"):
                self.openPlayList()

            elif os.path.isdir(arg):
                for root, dirs, files in os.walk(arg):
                    for file in files:
                        self.addToPlayList(os.path.join(root, file))
            else:
                self.addToPlayList(arg)
        self.playFirst(interrupt=False)


    def connect(self):
    # widgets
        self.mw.seekBar.valueChanged.connect(self.player.seek)
        self.mw.volumeBar.valueChanged.connect(self.player.setVolume)
        self.mw.playButton.clicked.connect(self.playClicked)
        self.mw.nextButton.pressed.connect(self.nextSong)
        self.mw.prevButton.pressed.connect(self.prevSong)
        self.mw.clearButton.pressed.connect(self.playlist.clear)

        # player
        self.player.tick.connect(self.tick)
        self.player.sourceChanged.connect(self.sourceChanged)
        self.player.stateChanged.connect(self.stateChanged)
        self.player.finished.connect(self.nextSong)

        # tray actions
        self.trayIcon.actionNext.triggered.connect(self.nextSong)
        self.trayIcon.actionPrev.triggered.connect(self.prevSong)
        self.trayIcon.clicked.connect(self.trayClicked)
        self.trayIcon.installEventFilter(self)

        # app
        qApp.aboutToQuit.connect(self.saveSettings)
        self.mw.actionQuit.triggered.connect(qApp.quit)
        self.mw.actionOpenPL.triggered.connect(self.openPlayList)


    def hotKeys(self):
        scHide = QShortcut(QKeySequence(self.tr('Esc', 'Escape')), self.mw);
        scHide.activated.connect(self.showHide)

    @dbus.service.method('com.phonik.PhonikInterface')
    def showHide(self):
        if self.mw.isHidden():
            self.mw.show()
        elif self.mw.isMinimized():
            self.mw.showNormal();
        else:
            if self.mw.isActiveWindow():
                self.mw.setHidden(True)
            else:
                self.mw.raise_()
                self.mw.activateWindow()


    def trayClicked(self, reason):
        if reason == QSystemTrayIcon.Trigger:
            self.showHide()

        elif reason == QSystemTrayIcon.MiddleClick:
            self.player.pause()


    def saveSettings(self):
        self.pm.unloadPlugins()
        set('app.pos', self.mw.saveGeometry())
        set('playlist.columns', self.playlist.getState())
        set('player.repeat', self.mw.repeatButton.isChecked())
        set('player.volume', self.mw.volumeBar.value())

        save()


    def readSettings(self):
        if configCreated():
            self.mw.restoreGeometry(get('app.pos', '0'))
            self.playlist.setState(get('playlist.columns', '0'))
            self.mw.volumeBar.setValue(int(get('player.volume', 100)))
            self.mw.repeatButton.setChecked(eval(get('player.repeat', 'True')))
        else:
            self.firstRun()


    def firstRun(self):
        self.playlist.setColumnWidth_(0, 40)
        self.playlist.setColumnWidth_(2, 140)
        self.playlist.setColumnWidth_(3, 140)
        self.playlist.setColumnWidth_(5, 80)
        self.playlist.setColumnHidden_(4, True)
        self.playlist.setColumnHidden_(6, True)
        self.playlist.setColumnHidden_(7, True)
        self.playlist.setSortingColumn(1)
        self.mw.volumeBar.setValue(100)
        self.mw.move(300, 300)


    def notify(self, string):
        self.mw.mainLabel.setText(QString.fromUtf8(string))


    def tick(self, time):
        self.mw.seekBar.blockSignals(True)
        self.mw.seekBar.setValue(time)
        self.mw.seekBar.update()
        self.mw.seekBar.blockSignals(False)


    def sourceChanged(self):
        self.mw.mainLabel.setText(self.playlist.getCurrentTitle())

        # reset positions
        self.mw.seekBar.blockSignals(True)
        self.mw.seekBar.setMaximum(self.player.getDuration())
        self.mw.seekBar.reset()
        self.mw.seekBar.blockSignals(False)


    def stateChanged(self, oldState, newState):
        if newState == gst.STATE_PLAYING:
            self.mw.playButton.setChecked(True)
            self.trayIcon.setIcon(self.mw.style().standardIcon(QStyle.SP_MediaPlay))
        else:
            self.mw.playButton.setChecked(False)
            self.trayIcon.setIcon(self.mw.style().standardIcon(QStyle.SP_MediaStop))


    def openPlayList(self, fileName):
        if not fileName:
            fileName = QFileDialog.getOpenFileName(self.mw, self.tr('Choose a file'),
                                                   QDesktopServices.storageLocation(QDesktopServices.MusicLocation),
                                                   filter='*.m3u *.pls')
            fileName = unicode(fileName.toUtf8(), 'utf-8')
        dirPath = os.path.dirname(fileName)

        self.playlist.clear()
        for line in open(fileName).readlines():
            if fileName.lower().endswith(".m3u"):
                line = line.strip()
                if not line.startswith('#') and line != '':
                    if line.startswith('http://'):
                        self.player.play(line)
                        return
                    else:
                        path = dirPath + os.sep + line
                        path = path.replace('\\', '/').strip()
                        self.addToPlayList(path)

            elif fileName.lower().endswith(".pls"):
                if line.strip().startswith('File'):
                    file = line[line.find('=') + 1:]

                    if file.startswith('http://'):
                        self.player.play(file)
                        return
                    else:
                        path = dirPath + os.sep + file
                        path = path.replace('\\', '/').strip()
                        self.addToPlayList(path)
        self.playFirst()


    def addToPlayList(self, path):
        if self.informer.hasAudio(path):
            url, info, tags = self.informer.getInfo(path)
            if info:
                self.playlist.addSong(url, info, tags, False)


    def playClicked(self, play):
        print 'playClicked'

        # if player has song set
        if self.player.getCurrentSong() is not None:

        # if player is working,
            if not self.player.isStopped():
                if play:
                    self.player.play()
                else:
                    self.player.pause()
        else:
            self.mw.playButton.setChecked(False)


    def eventFilter(self, object, event):
        if object is self.trayIcon and event.type() == QEvent.Wheel:
            delta = event.delta()


            #if the middle mouse button is held
            if qApp.mouseButtons() == Qt.MidButton:
                if delta > 0:
                    self.prevSong()
                else:
                    self.nextSong()
            else:
                if delta > 0:
                #increase volume
                    self.mw.volumeBar.setValue(self.mw.volumeBar.value() + 10)
                else:
                #decrease volume
                    self.mw.volumeBar.setValue(self.mw.volumeBar.value() - 10)

                    #self.showMessage(self.tr('Volume'), str(self.phonik.py.mw.volumeBar.value() ) + '%', QSystemTrayIcon.NoIcon, 700)

            event.accept()
            return True

        return False


    def nextSong(self):
        row = self.playlist.currentRow()
        if row < self.playlist.rowCount() - 1:
            self.player.play(self.playlist.getSongURI(row + 1))
            self.playlist.setCurrentRow(row + 1)
        elif self.mw.repeatButton.isChecked():
            self.playFirst()


    def prevSong(self):
        row = self.playlist.currentRow()
        if row > 0:
            self.player.play(self.playlist.getSongURI(row - 1))
            self.playlist.setCurrentRow(row - 1)


    def playFirst(self, interrupt=None):
        if self.player.isPlaying():
            if not interrupt:
                return
            self.player.stop()

        self.playlist.selectFirst()
        self.player.play(self.playlist.getSongURI(0))


